package impl.reasoning;

import impl.util.UtilityAssertion;
import interfaces.UDecideReasonerInterface;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;

import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLNamedIndividual;
import org.semanticweb.owlapi.owllink.OWLlinkReasonerRuntimeException;
import org.semanticweb.owlapi.reasoner.Node;
import org.semanticweb.owlapi.reasoner.NodeSet;
import org.semanticweb.owlapi.reasoner.OWLReasoner;

import exceptions.UDecideReasonerRuntimeException;

public class UDecideReasoner implements UDecideReasonerInterface {

	private OWLReasoner										reasoner;
	private Collection<UtilityAssertion>					uAssertions;
	private Map<OWLNamedIndividual, ChoiceResult>	choiceResults;
	private Map<UtilityAssertion, Set<OWLNamedIndividual>>	uAssertionResults;
	private HashMap<UtilityAssertion, OWLClass>				dummyClasses;

	@Override
	public Map<OWLNamedIndividual, ChoiceResult> getAllChoiceResults() {
		return this.choiceResults;
	}

	@Override
	public ChoiceResult getChoiceResult(OWLNamedIndividual choice) {
		if (this.choiceResults.containsKey(choice)) {
			return this.choiceResults.get(choice);
		} else {
			return new ChoiceResult(choice);
		}
	}

	@Override
	public Collection<OWLNamedIndividual> getSatisfyingChoicesForUtilityAssertion(UtilityAssertion uAssertion) {
		if (this.uAssertionResults.containsKey(uAssertion)) {
			return this.uAssertionResults.get(uAssertion);
		} else {
			return new LinkedList<OWLNamedIndividual>();
		}
	}

	public void calculateChoiceResults() throws UDecideReasonerRuntimeException {
		for (UtilityAssertion u : this.uAssertions) { // get instances for each
			// utility assertion

			OWLClass uAssertionDummyClass = this.dummyClasses.get(u);

			try {
				Set<OWLNamedIndividual> satisfyingIndividuals = getIndividualSetFromIndividualNodeSet(this.reasoner.getInstances(uAssertionDummyClass, true));

				this.uAssertionResults.put(u, satisfyingIndividuals);

				for (OWLNamedIndividual indi : satisfyingIndividuals) {
					addUtilityAssertionToChoiceResult(indi, u); // add
					// utilityAsserton
					// to all
					// individuals's
					// reasoningResult
					// that satisfy
					// it
				}
			} catch (OWLlinkReasonerRuntimeException re) {
				throw new UDecideReasonerRuntimeException(re.getMessage());
			}

		}
	}

	public UDecideReasoner(OWLReasoner reasoner, Collection<UtilityAssertion> collection, HashMap<UtilityAssertion, OWLClass> dummyClasses) {
		this.reasoner = reasoner;
		this.uAssertions = collection;
		this.dummyClasses = dummyClasses;

		this.choiceResults = new HashMap<OWLNamedIndividual, ChoiceResult>();
		this.uAssertionResults = new HashMap<UtilityAssertion, Set<OWLNamedIndividual>>();
	}

	private void addUtilityAssertionToChoiceResult(OWLNamedIndividual choice, UtilityAssertion u) {
		if (!this.choiceResults.containsKey(choice)) {
			ChoiceResult indiReasoningResult = new ChoiceResult(choice);
			indiReasoningResult.addInferredUtilityAssertion(u);
			this.choiceResults.put(choice, indiReasoningResult);
		} else {
			this.choiceResults.get(choice).addInferredUtilityAssertion(u);
		}
	}

	private static Set<OWLNamedIndividual> getIndividualSetFromIndividualNodeSet(NodeSet<OWLNamedIndividual> instances) {
		HashSet<OWLNamedIndividual> indis = new HashSet<OWLNamedIndividual>();

		for (Node<OWLNamedIndividual> n : instances) {
			for (OWLNamedIndividual indi : n) {
				indis.add(indi);
			}
		}

		return indis;
	}
}
